{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Detect explicit, suggestive and violent content using Amazon Rekognition"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook provides a walkthrough of [content moderation APIs](https://docs.aws.amazon.com/rekognition/latest/dg/moderation.html) in Amazon Rekognition. You can quickly identify inappropriate content in your video and image libraries."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import boto3\n",
    "from IPython.display import Image as IImage, display\n",
    "from IPython.display import HTML, display\n",
    "from PIL import Image, ImageDraw, ImageFont\n",
    "import time\n",
    "import os"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sagemaker\n",
    "import boto3\n",
    "\n",
    "sagemaker_session = sagemaker.Session()\n",
    "role = sagemaker.get_execution_role()\n",
    "bucket = sagemaker_session.default_bucket()\n",
    "region = boto3.Session().region_name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rekognition = boto3.client(\"rekognition\")\n",
    "s3 = boto3.client(\"s3\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Content Moderation in Images"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "imageName = \"content-moderation/media/weapon.png\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Call Rekognition to Detect Unsafe Objects in the Image\n",
    "Call Amazon Rekognition to detect unsafe content in the image: https://docs.aws.amazon.com/rekognition/latest/dg/moderation.html\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "detectModerationLabelsResponse = rekognition.detect_moderation_labels(\n",
    "    Image={\n",
    "        \"S3Object\": {\n",
    "            \"Bucket\": bucket,\n",
    "            \"Name\": imageName,\n",
    "        }\n",
    "    }\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "display(IImage(url=s3.generate_presigned_url(\"get_object\", Params={\"Bucket\": bucket, \"Key\": imageName})))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Review JSON Response from Rekognition Moderation API\n",
    "\n",
    "In the JSON response below, you will see Moderation Labels, confidence score and additional information.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "display(detectModerationLabelsResponse)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Display list of detected moderation labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for label in detectModerationLabelsResponse[\"ModerationLabels\"]:\n",
    "    print(\"- {} (Confidence: {})\".format(label[\"Name\"], label[\"Confidence\"]))\n",
    "    print(\"  - Parent: {}\".format(label[\"ParentName\"]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Content Moderation in Video\n",
    "\n",
    "Content Moderation in video is an async operation. \n",
    "https://docs.aws.amazon.com/rekognition/latest/dg/API_StartContentModeration.html\n",
    " - We first start content moderation job which returns a Job Id.\n",
    " - We can then call `get_content_moderation` to get the job status and after job is complete, we can get moderation results.\n",
    " - In production use cases, you would usually use StepFucntion or SNS topic to get notified when job is complete."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "videoName = \"content-moderation/media/weapon.mp4\"\n",
    "\n",
    "strDetail = \"Moderation labels in video<br>=======================================<br>\"\n",
    "strOverall = \"Moderation labels in the overall video:<br>=======================================<br>\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "s3VideoUrl = s3.generate_presigned_url(\"get_object\", Params={\"Bucket\": bucket, \"Key\": videoName})\n",
    "\n",
    "videoTag = \"<video controls='controls' autoplay width='640' height='360' name='Video' src='{0}'></video>\".format(\n",
    "    s3VideoUrl\n",
    ")\n",
    "\n",
    "videoui = \"<table><tr><td style='vertical-align: top'>{}</td></tr></table>\".format(videoTag)\n",
    "\n",
    "display(HTML(videoui))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Call Rekognition to Start a Job for Content Moderation\n",
    "\n",
    "### Additional (Optional) Request Attributes\n",
    "\n",
    "ClientRequestToken:\n",
    "https://docs.aws.amazon.com/rekognition/latest/dg/API_StartContentModeration.html#rekognition-StartContentModeration-request-ClientRequestToken\n",
    "\n",
    "JobTag:\n",
    "https://docs.aws.amazon.com/rekognition/latest/dg/API_StartContentModeration.html#rekognition-StartContentModeration-request-JobTag\n",
    "\n",
    "MinConfidence:\n",
    "https://docs.aws.amazon.com/rekognition/latest/dg/API_StartContentModeration.html#rekognition-StartContentModeration-request-MinConfidence\n",
    "\n",
    "NotificationChannel:\n",
    "https://docs.aws.amazon.com/rekognition/latest/dg/API_StartContentModeration.html#rekognition-StartContentModeration-request-NotificationChannel\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Start content moderation job\n",
    "startModerationLabelDetection = rekognition.start_content_moderation(\n",
    "    Video={\n",
    "        \"S3Object\": {\n",
    "            \"Bucket\": bucket,\n",
    "            \"Name\": videoName,\n",
    "        }\n",
    "    },\n",
    "    MinConfidence=50.0\n",
    ")\n",
    "\n",
    "moderationJobId = startModerationLabelDetection[\"JobId\"]\n",
    "display(\"Job Id: {0}\".format(moderationJobId))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Wait for content moderation job to complete\n",
    "In production use cases, you would usually use StepFunction or SNS topic to get notified when job is complete.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "\n",
    "getContentModeration = rekognition.get_content_moderation(JobId=moderationJobId, SortBy=\"TIMESTAMP\")\n",
    "\n",
    "while getContentModeration[\"JobStatus\"] == \"IN_PROGRESS\":\n",
    "    time.sleep(5)\n",
    "    print(\".\", end=\"\")\n",
    "\n",
    "    getContentModeration = rekognition.get_content_moderation(JobId=moderationJobId, SortBy=\"TIMESTAMP\")\n",
    "\n",
    "display(getContentModeration[\"JobStatus\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Review JSON response returned by Rekognition Content Moderation API\n",
    "\n",
    "In the JSON response below, you will see list of detected content.\n",
    "\n",
    "For each detected object, you will see `Timestamp`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "display(getContentModeration)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Display List of Unsafe Content in the Video"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "theObjects = {}\n",
    "\n",
    "# Potentially unsafe detected in each frame\n",
    "for obj in getContentModeration[\"ModerationLabels\"]:\n",
    "    ts = obj[\"Timestamp\"]\n",
    "    cconfidence = obj[\"ModerationLabel\"][\"Confidence\"]\n",
    "    oname = obj[\"ModerationLabel\"][\"Name\"]\n",
    "    strDetail = strDetail + \"At {} ms: {} (Confidence: {})<br>\".format(ts, oname, round(cconfidence, 2))\n",
    "    if oname in theObjects:\n",
    "        cojb = theObjects[oname]\n",
    "        theObjects[oname] = {\"Name\": oname, \"Count\": 1 + cojb[\"Count\"]}\n",
    "    else:\n",
    "        theObjects[oname] = {\"Name\": oname, \"Count\": 1}\n",
    "\n",
    "# Unique objects detected in video\n",
    "for theObject in theObjects:\n",
    "    strOverall = strOverall + \"Name: {}, Count: {}<br>\".format(theObject, theObjects[theObject][\"Count\"])\n",
    "\n",
    "# Display results\n",
    "display(HTML(strOverall))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "listui = \"<table><tr><td style='vertical-align: top'>{}</td></tr></table>\".format(strDetail)\n",
    "display(HTML(listui))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# References\n",
    "- https://docs.aws.amazon.com/rekognition/latest/dg/API_DetectModerationLabels.html\n",
    "- https://docs.aws.amazon.com/rekognition/latest/dg/API_StartContentModeration.html\n",
    "- https://docs.aws.amazon.com/rekognition/latest/dg/API_GetContentModeration.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Congratulations!\n",
    "You just detected explicit, suggestive and violent content using Amazon Rekognition."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Release Resources"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%html\n",
    "\n",
    "<p><b>Shutting down your kernel for this notebook to release resources.</b></p>\n",
    "<button class=\"sm-command-button\" data-commandlinker-command=\"kernelmenu:shutdown\" style=\"display:none;\">Shutdown Kernel</button>\n",
    "        \n",
    "<script>\n",
    "try {\n",
    "    els = document.getElementsByClassName(\"sm-command-button\");\n",
    "    els[0].click();\n",
    "}\n",
    "catch(err) {\n",
    "    // NoOp\n",
    "}    \n",
    "</script>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%javascript\n",
    "\n",
    "try {\n",
    "    Jupyter.notebook.save_checkpoint();\n",
    "    Jupyter.notebook.session.delete();\n",
    "}\n",
    "catch(err) {\n",
    "    // NoOp\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "instance_type": "ml.t3.medium",
  "kernelspec": {
   "display_name": "Python 3 (Data Science)",
   "language": "python",
   "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/datascience-1.0"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
